﻿// -----------------------------------------------------------------------
//    This file is part of TSGE.
//
//    TSGE is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 2 of the License, or
//    (at your option) any later version.
//
//    TSGE is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with TSGE.  If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using tsge.Classes;

namespace tsge.Controls
{
    /// <summary>
    /// Interaction logic for CharacterEditor.xaml
    /// 
    ///     Inherits:
    ///         - UserControl
    /// </summary>
    public partial class CharacterEditor : System.Windows.Controls.UserControl
    {
        /// <summary>
        /// Default Constructor
        /// </summary>
        public CharacterEditor()
        {
            InitializeComponent();

            // Initialize Difficulty Settings
            this.cboDifficulty.ItemsSource = new String[] 
            { 
                "Softcore", "Mediumcore", "Hardcore"
            };

            // Initialize Health and Mana Labels
            this.lblHealth.Content = String.Format("{0}/{1}", this.pbHealth.Value, this.pbHealth.Maximum);
            this.lblMana.Content = String.Format("{0}/{1}", this.pbMana.Value, this.pbMana.Maximum);
            this.lblMaxHealth.Content = String.Format("{0}/{1}", this.pbMaxHealth.Value, this.pbMaxHealth.Maximum);
            this.lblMaxMana.Content = String.Format("{0}/{1}", this.pbMaxMana.Value, this.pbMaxMana.Maximum);

            // Attach DataContextChanged Events To Update Model Viewer
            this.rcColorHair.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.HairColor = (e.NewValue as Player).HairColor;
            });
            this.rcColorSkin.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.HeadColor =
                    this.modelViewer.HandsColor = (e.NewValue as Player).SkinColor;
            });
            this.rcColorEyes.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.EyeColor = (e.NewValue as Player).EyeColor;
            });
            this.rcColorShirt.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.ShirtColor = (e.NewValue as Player).ShirtColor;
            });
            this.rcColorUnderShirt.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.UnderShirtColor = (e.NewValue as Player).UnderShirtColor;
            });
            this.rcColorPants.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.PantsColor = (e.NewValue as Player).PantsColor;
            });
            this.rcColorShoes.DataContextChanged += new DependencyPropertyChangedEventHandler((sender, e) =>
            {
                if (e.NewValue is Player)
                    this.modelViewer.ShoesColor = (e.NewValue as Player).ShoesColor;
            });
        }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// PLAYER PROFILE TAB
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Event handler for when the health progress bar value is changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbHealth_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this.lblHealth != null)
                this.lblHealth.Content = String.Format("{0}/{1}", this.pbHealth.Value, this.pbHealth.Maximum);
        }

        /// <summary>
        /// Event handler for when the mana progress bar value is changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMana_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this.lblMana != null)
                this.lblMana.Content = String.Format("{0}/{1}", this.pbMana.Value, this.pbMana.Maximum);
        }

        /// <summary>
        /// Event handler for when the max health progress bar value is changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMaxHealth_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this.lblMaxHealth != null)
                this.lblMaxHealth.Content = String.Format("{0}/{1}", this.pbMaxHealth.Value, this.pbMaxHealth.Maximum);

            this.pbHealth.Maximum = this.pbMaxHealth.Value;

            if (this.lblHealth != null)
                this.lblHealth.Content = String.Format("{0}/{1}", this.pbHealth.Value, this.pbHealth.Maximum);
        }

        /// <summary>
        /// Event handler for when the max mana progress bar value is changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMaxMana_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this.lblMaxMana != null)
                this.lblMaxMana.Content = String.Format("{0}/{1}", this.pbMaxMana.Value, this.pbMaxMana.Maximum);

            this.pbMana.Maximum = this.pbMaxMana.Value;

            if (this.lblMana != null)
                this.lblMana.Content = String.Format("{0}/{1}", this.pbMana.Value, this.pbMana.Maximum);
        }

        /// <summary>
        /// Event handler for updating the health progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbHealth_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            double dblMousePosX = e.GetPosition(this.pbHealth).X;
            double dblRatio = dblMousePosX / this.pbHealth.ActualWidth;
            this.pbHealth.Value = (int)(dblRatio * this.pbHealth.Maximum);
        }

        /// <summary>
        /// Event handler for updating the mana progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMana_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            double dblMousePosX = e.GetPosition(this.pbMana).X;
            double dblRatio = dblMousePosX / this.pbMana.ActualWidth;
            this.pbMana.Value = (int)(dblRatio * this.pbMana.Maximum);
        }

        /// <summary>
        /// Event handler for updating the health progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbHealth_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                double dblMousePosX = e.GetPosition(this.pbHealth).X;
                double dblRatio = dblMousePosX / this.pbHealth.ActualWidth;
                this.pbHealth.Value = (int)(dblRatio * this.pbHealth.Maximum);
            }
        }

        /// <summary>
        /// Event handler for updating the mana progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMana_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                double dblMousePosX = e.GetPosition(this.pbMana).X;
                double dblRatio = dblMousePosX / this.pbMana.ActualWidth;
                this.pbMana.Value = (int)(dblRatio * this.pbMana.Maximum);
            }
        }

        /// <summary>
        /// Event handler for updating the max health progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMaxHealth_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            double dblMousePosX = e.GetPosition(this.pbMaxHealth).X;
            double dblRatio = dblMousePosX / this.pbMaxHealth.ActualWidth;
            this.pbMaxHealth.Value = (int)(dblRatio * this.pbMaxHealth.Maximum);
        }

        /// <summary>
        /// Event handler for updating the max health progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMaxHealth_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                double dblMousePosX = e.GetPosition(this.pbMaxHealth).X;
                double dblRatio = dblMousePosX / this.pbMaxHealth.ActualWidth;
                this.pbMaxHealth.Value = (int)(dblRatio * this.pbMaxHealth.Maximum);
            }
        }

        /// <summary>
        /// Event handler for updating the max mana progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMaxMana_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            double dblMousePosX = e.GetPosition(this.pbMaxMana).X;
            double dblRatio = dblMousePosX / this.pbMaxMana.ActualWidth;
            this.pbMaxMana.Value = (int)(dblRatio * this.pbMaxMana.Maximum);
        }

        /// <summary>
        /// Event handler for updating the max mana progress bar value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbMaxMana_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                double dblMousePosX = e.GetPosition(this.pbMaxMana).X;
                double dblRatio = dblMousePosX / this.pbMaxMana.ActualWidth;
                this.pbMaxMana.Value = (int)(dblRatio * this.pbMaxMana.Maximum);
            }
        }

        /// <summary>
        /// Click event to allow changing the model hair color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorHair_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.HairColor = cDialog.Color.ToMColor();
                    this.rcColorHair.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }

        /// <summary>
        /// Click event to allow changing the model skin color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorSkin_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.HandsColor = cDialog.Color.ToMColor();
                    this.modelViewer.HeadColor = cDialog.Color.ToMColor();
                    this.rcColorSkin.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }

        /// <summary>
        /// Click event to allow changing the model eyes color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorEyes_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.EyeColor = cDialog.Color.ToMColor();
                    this.rcColorEyes.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }

        /// <summary>
        /// Click event to allow changing the model shirt color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorShirt_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.ShirtColor = cDialog.Color.ToMColor();
                    this.rcColorShirt.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }

        /// <summary>
        /// Click event to allow changing the model undershirt color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorUnderShirt_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.UnderShirtColor = cDialog.Color.ToMColor();
                    this.rcColorUnderShirt.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }

        /// <summary>
        /// Click event to allow changing the model pants color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorPants_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.PantsColor = cDialog.Color.ToMColor();
                    this.rcColorPants.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }

        /// <summary>
        /// Click event to allow changing the model shoes color.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rcColorShoes_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            using (ColorDialog cDialog = new ColorDialog())
            {
                cDialog.AllowFullOpen = true;
                cDialog.AnyColor = true;

                DialogResult dlgResult = cDialog.ShowDialog();
                if (dlgResult == DialogResult.OK)
                {
                    this.modelViewer.ShoesColor = cDialog.Color.ToMColor();
                    this.rcColorShoes.Fill = new SolidColorBrush(cDialog.Color.ToMColor());
                }
            }
        }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// BUFFS TAB
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// Event handler to update the selected buff.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstBuffList_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (this.lstBuffEntries.SelectedIndex == -1)
                return;

            dynamic buff = this.lstBuffEntries.Items[this.lstBuffEntries.SelectedIndex];
            buff.SetBuff((this.lstBuffList.SelectedItem as Buff).Id);
        }

        /// <summary>
        /// Click handler to remove all buffs.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRemoveAllBuffs_Click(object sender, RoutedEventArgs e)
        {
            foreach (Buff buff in this.lstBuffEntries.Items)
                buff.SetBuff(0);
        }

        /// <summary>
        /// Click handler to set all buff durations to 30 minutes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnHackedDurations_Click(object sender, RoutedEventArgs e)
        {
            var buffs = (from Buff buff in this.lstBuffEntries.Items
                         where buff.Id > 0
                         select buff);

            foreach (Buff buff in buffs)
                buff.Duration = 108000;
        }

        /// <summary>
        /// Click handler to set all buff durations to their max value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMaxBuffDurations_Click(object sender, RoutedEventArgs e)
        {
            var buffs = (from Buff buff in this.lstBuffEntries.Items
                         where buff.Id > 0
                         select buff);

            foreach (Buff buff in buffs)
            {
                var b = (from Buff currbuff in Terraria.Instance.Buffs
                         where currbuff.Id == buff.Id
                         select currbuff).SingleOrDefault() as Buff;
                buff.Duration = b.Duration;
            }
        }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// INVENTORY TAB
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// Event handler to update the available items for the selected inventory slot.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstInventoryEntries_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // User selecting a coin slot..
            if (this.lstInventoryEntries.SelectedIndex > 39 && this.lstInventoryEntries.SelectedIndex <= 43)
            {
                this.cboInventoryItem.ItemsSource = (from item in Terraria.Instance.Items where item.Name.Contains("Coin") || item.Id == 0 
                                                     select item).ToList();
            }

            // User selecting an ammo slot..
            else if (this.lstInventoryEntries.SelectedIndex > 43)
            {
                this.cboInventoryItem.ItemsSource = (from item in Terraria.Instance.Items where item.Ammo > 0 || item.Id == 0 
                                                     select item).ToList();
            }

            // User selecting normal inventory slot..
            else
            {
                this.cboInventoryItem.ItemsSource = Terraria.Instance.Items;
            }
        }

        /// <summary>
        /// Enables right-click 'duping' of items inside inventory.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstInventoryEntries_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var item = this.lstInventoryEntries.SelectedItem as Item;

            if (item != null)
            {
                if (this.cboInventoryItem.SelectedItem is Item)
                {
                    if (this.lstInventoryEntries.SelectedIndex > 39 && this.lstInventoryEntries.SelectedIndex <= 43)
                    {
                        // Item must be ammo type..
                        if (!((this.cboInventoryItem.SelectedItem as Item).Ammo > 0))
                            return;

                        item.SetItem((this.cboInventoryItem.SelectedItem as Item).Id);
                        item.Count = item.Stack = (this.cboInventoryItem.SelectedItem as Item).MaxStack;

                        Int32 nCount = 0;
                        if (Int32.TryParse(this.txtInventoryAmount.Text, out nCount))
                        {
                            item.Count = item.Stack = nCount;
                        }

                        if (item.Id == 0)
                        {
                            item.Count = item.Stack = 0;
                            return;
                        }

                        if (this.cboInventoryPrefix.SelectedItem is ItemPrefix)
                        {
                            item.Prefix = (byte)(this.cboInventoryPrefix.SelectedItem as ItemPrefix).Id;
                        }
                    }
                    else if (this.lstInventoryEntries.SelectedIndex > 43)
                    {
                        // Item must be a coin..
                        if (!(this.cboInventoryItem.SelectedItem as Item).Name.Contains("Coin"))
                            return;

                        item.SetItem((this.cboInventoryItem.SelectedItem as Item).Id);
                        item.Count = item.Stack = (this.cboInventoryItem.SelectedItem as Item).MaxStack;

                        Int32 nCount = 0;
                        if (Int32.TryParse(this.txtInventoryAmount.Text, out nCount))
                        {
                            item.Count = item.Stack = nCount;
                        }

                        if (item.Id == 0)
                        {
                            item.Count = item.Stack = 0;
                            return;
                        }
                    }
                    else
                    {
                        item.SetItem((this.cboInventoryItem.SelectedItem as Item).Id);
                        item.Count = item.Stack = (this.cboInventoryItem.SelectedItem as Item).MaxStack;

                        Int32 nCount = 0;
                        if (Int32.TryParse(this.txtInventoryAmount.Text, out nCount))
                        {
                            item.Count = item.Stack = nCount;
                        }

                        if (item.Id == 0)
                        {
                            item.Count = item.Stack = 0;
                            return;
                        }

                        if (this.cboInventoryPrefix.SelectedItem is ItemPrefix)
                        {
                            item.Prefix = (byte)(this.cboInventoryPrefix.SelectedItem as ItemPrefix).Id;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Event handler to update the selected item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboInventoryItem_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Prevent invalid updates when the combobox items source is updated..
            if (this.cboInventoryItem.SelectedItem == null ||
                this.cboInventoryItem.SelectedIndex == -1 ||
                this.lstInventoryEntries.SelectedItem == null)
                return;

            var item = this.lstInventoryEntries.SelectedItem as Item;
            item.SetItem((this.cboInventoryItem.SelectedItem as Item).Id);
            item.Count = item.Stack = item.MaxStack;
        }

        /// <summary>
        /// Event handler to update the selected items prefix.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboInventoryPrefix_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // Prevent invalid updates..
            if (this.cboInventoryPrefix.SelectedItem == null ||
                this.cboInventoryPrefix.SelectedIndex == -1 ||
                this.lstInventoryEntries.SelectedItem == null ||
                (this.lstInventoryEntries.SelectedItem as Item).Id == 0)
                return;

            var item = this.lstInventoryEntries.SelectedItem as Item;
            item.Prefix = (byte)(this.cboInventoryPrefix.SelectedItem as ItemPrefix).Id;
        }

        /// <summary>
        /// Event handler to update the selected items prefix.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboInventoryPrefix_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Prevent invalid updates..
            if (this.cboInventoryPrefix.SelectedItem == null ||
                this.cboInventoryPrefix.SelectedIndex == -1 ||
                this.lstInventoryEntries.SelectedItem == null ||
                (this.lstInventoryEntries.SelectedItem as Item).Id == 0)
                return;

            var item = this.lstInventoryEntries.SelectedItem as Item;
            item.Prefix = (byte)(this.cboInventoryPrefix.SelectedItem as ItemPrefix).Id;
        }

        /// <summary>
        /// Event handler to prevent non-numerical keys inside the amout box.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtInventoryAmount_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if ((!(e.Key < Key.D0 || e.Key > Key.D9) ||
                (!(e.Key < Key.NumPad0 || e.Key > Key.NumPad9))) && !Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
            {
                e.Handled = false;
            }
            else
            {
                e.Handled = !(
                    e.Key == Key.Back || e.Key == Key.Delete ||
                    e.Key == Key.Up || e.Key == Key.Down ||
                    e.Key == Key.Left || e.Key == Key.Right
                    );
            }
        }

        /// <summary>
        /// Event handler to update the selected items count.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtInventoryAmount_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Prevent invalid updates..
            if (this.lstInventoryEntries.SelectedItem == null)
                return;

            var item = this.lstInventoryEntries.SelectedItem as Item;
            if (item.Id == 0) return;

            var count = 0;
            if (Int32.TryParse(this.txtInventoryAmount.Text, out count))
                item.Count = count;
        }

        /// <summary>
        /// Click event to remove all items.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDeleteAllItems_Click(object sender, RoutedEventArgs e)
        {
            var items = (from Item item in this.lstInventoryEntries.Items
                         where item.Id != 0
                         select item).ToList();

            items.ForEach(x => { x.SetItem(0); x.Count = 0; });
        }

        /// <summary>
        /// Click event to set all item stacks to their max.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetMaxStacks_Click(object sender, RoutedEventArgs e)
        {
            var items = (from Item item in this.lstInventoryEntries.Items
                         where item.Id != 0
                         select item).ToList();

            items.ForEach(x => { x.Count = x.Stack = x.MaxStack; });
        }

        /// <summary>
        /// Click event to set all item stacks to 999.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetHackedStacks_Click(object sender, RoutedEventArgs e)
        {
            var items = (from Item item in this.lstInventoryEntries.Items
                         where item.Id != 0 && item.MaxStack > 1
                         select item).ToList();

            items.ForEach(x => { x.Count = x.Stack = 999; });
        }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// EQUIPMENT TAB
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// Event handler to update the selected item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentList_MouseUp(object sender, MouseButtonEventArgs e)
        {
            dynamic item = null;

            if (this.lstEquipmentArmor.SelectedIndex > -1)
                item = this.lstEquipmentArmor.SelectedItem;
            if (this.lstEquipmentVanity.SelectedIndex > -1)
                item = this.lstEquipmentVanity.SelectedItem;
            if (this.lstEquipmentAccessories.SelectedIndex > -1)
                item = this.lstEquipmentAccessories.SelectedItem;

            if (item != null)
                item.SetItem((this.lstEquipmentList.SelectedItem as Item).Id);
        }

        /// <summary>
        /// Event handler to update the selected item prefix.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboEquipmentPrefixList_MouseUp(object sender, MouseButtonEventArgs e)
        {
            dynamic item = null;

            if (this.lstEquipmentArmor.SelectedIndex > -1)
                item = this.lstEquipmentArmor.SelectedItem;
            if (this.lstEquipmentVanity.SelectedIndex > -1)
                item = this.lstEquipmentVanity.SelectedItem;
            if (this.lstEquipmentAccessories.SelectedIndex > -1)
                item = this.lstEquipmentAccessories.SelectedItem;

            if (item != null)
                item.Prefix = (byte)(this.cboEquipmentPrefixList.SelectedItem as ItemPrefix).Id;
        }

        /// <summary>
        /// Event handler to update the selecteditems prefix.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboEquipmentPrefixList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            dynamic item = null;

            if (this.lstEquipmentArmor.SelectedIndex > -1)
                item = this.lstEquipmentArmor.SelectedItem;
            if (this.lstEquipmentVanity.SelectedIndex > -1)
                item = this.lstEquipmentVanity.SelectedItem;
            if (this.lstEquipmentAccessories.SelectedIndex > -1)
                item = this.lstEquipmentAccessories.SelectedItem;

            if (item != null)
                item.Prefix = (byte)(this.cboEquipmentPrefixList.SelectedItem as ItemPrefix).Id;
        }

        /// <summary>
        /// Event handler to update the selected item. Deselects other items.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentArmor_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.lstEquipmentVanity.SelectedIndex = -1;
            this.lstEquipmentAccessories.SelectedIndex = -1;
        }

        /// <summary>
        /// Event handler to update the selected item. Deselects other items.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentVanity_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.lstEquipmentArmor.SelectedIndex = -1;
            this.lstEquipmentAccessories.SelectedIndex = -1;
        }

        /// <summary>
        /// Event handler to update the selected item. Deselects other items.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentAccessories_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.lstEquipmentArmor.SelectedIndex = -1;
            this.lstEquipmentVanity.SelectedIndex = -1;
        }

        /// <summary>
        /// Event handler to update the item list based on the item slot.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentArmor_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            switch (this.lstEquipmentArmor.SelectedIndex)
            {
                case 0: // head
                    this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.HeadSlot > -1 select item);
                    break;
                case 1: // body
                    this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.BodySlot > -1 select item);
                    break;
                case 2: // feet
                    this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.LegSlot > -1 select item);
                    break;
            }
        }

        /// <summary>
        /// Event handler to update the item list based on the item slot.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentVanity_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            switch (this.lstEquipmentVanity.SelectedIndex)
            {
                case 0: // head
                    this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.HeadSlot > -1 select item);
                    break;
                case 1: // body
                    this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.BodySlot > -1 select item);
                    break;
                case 2: // feet
                    this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.LegSlot > -1 select item);
                    break;
            }
        }

        /// <summary>
        /// Event handler to update the item list based on the item slot.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstEquipmentAccessories_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (this.lstEquipmentAccessories.SelectedIndex == -1) return;
            this.lstEquipmentList.ItemsSource = (from item in Terraria.Instance.Items where item.Accessory == true select item);
        }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// BANK + SAFE TAB
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// Event handler to update the selected item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstBankItemList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            dynamic item = null;

            if (this.lstBankItems.SelectedIndex > -1)
                item = this.lstBankItems.SelectedItem;
            if (this.lstSafeItems.SelectedIndex > -1)
                item = this.lstSafeItems.SelectedItem;

            if (item != null)
            {
                item.SetItem((this.lstBankItemList.SelectedItem as Item).Id);
                item.Count = item.Stack = (this.lstBankItemList.SelectedItem as Item).MaxStack;
                if (item.Id == 0) item.Count = item.Stack = 0;
            }
        }

        /// <summary>
        /// Event handler to update the selected item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstBankItemList_MouseUp(object sender, MouseButtonEventArgs e)
        {
            dynamic item = null;

            if (this.lstBankItems.SelectedIndex > -1)
                item = this.lstBankItems.SelectedItem;
            if (this.lstSafeItems.SelectedIndex > -1)
                item = this.lstSafeItems.SelectedItem;

            if (item != null)
            {
                item.SetItem((this.lstBankItemList.SelectedItem as Item).Id);
                item.Count = item.Stack = (this.lstBankItemList.SelectedItem as Item).MaxStack;
                if (item.Id == 0) item.Count = item.Stack = 0;
            }
        }

        /// <summary>
        /// Event handler to update the selected items prefix.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboBankItemPrefixList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            dynamic item = null;

            if (this.lstBankItems.SelectedIndex > -1)
                item = this.lstBankItems.SelectedItem;
            if (this.lstSafeItems.SelectedIndex > -1)
                item = this.lstSafeItems.SelectedItem;

            if (item != null && item.Id != 0 && this.cboBankItemPrefixList.SelectedItem is ItemPrefix)
                item.Prefix = (byte)(this.cboBankItemPrefixList.SelectedItem as ItemPrefix).Id;
        }

        /// <summary>
        /// Event handler to update the selected items prefix.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboBankItemPrefixList_MouseUp(object sender, MouseButtonEventArgs e)
        {
            dynamic item = null;

            if (this.lstBankItems.SelectedIndex > -1)
                item = this.lstBankItems.SelectedItem;
            if (this.lstSafeItems.SelectedIndex > -1)
                item = this.lstSafeItems.SelectedItem;

            if (item != null && item.Id != 0 && this.cboBankItemPrefixList.SelectedItem is ItemPrefix)
                item.Prefix = (byte)(this.cboBankItemPrefixList.SelectedItem as ItemPrefix).Id;
        }

        /// <summary>
        /// Event handler to prevent non-numerical keys inside the amout box.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtBankAmount_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if ((!(e.Key < Key.D0 || e.Key > Key.D9) ||
                (!(e.Key < Key.NumPad0 || e.Key > Key.NumPad9))) && !Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
            {
                e.Handled = false;
            }
            else
            {
                e.Handled = !(
                    e.Key == Key.Back || e.Key == Key.Delete || 
                    e.Key == Key.Up || e.Key == Key.Down ||
                    e.Key == Key.Left || e.Key == Key.Right
                    );
            }
        }

        /// <summary>
        /// Event handler to update the selected items count.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtBankAmount_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Prevent invalid updates..
            if (this.lstBankItems.SelectedItem == null && this.lstSafeItems.SelectedItem == null)
                return;

            var item = (this.lstBankItems.SelectedItem != null) ? this.lstBankItems.SelectedItem as Item : this.lstSafeItems.SelectedItem as Item;
            if (item.Id == 0) return;

            var count = 0;
            if (Int32.TryParse(this.txtBankAmount.Text, out count))
                item.Count = count;
        }

        /// <summary>
        /// Click handler to set items in bank and safe to their max stack count.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBankMaxItemStacks_Click(object sender, RoutedEventArgs e)
        {
            var bank = (from Item item in this.lstBankItems.Items
                        where item.Id != 0
                        select item).ToList();
            var safe = (from Item item in this.lstSafeItems.Items
                        where item.Id != 0
                        select item).ToList();

            bank.ForEach(x => { x.Count = x.Stack = x.MaxStack; });
            safe.ForEach(x => { x.Count = x.Stack = x.MaxStack; });
        }

        /// <summary>
        /// Click handler to set all items in bank and safe to 999.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBankHackItemStacks_Click(object sender, RoutedEventArgs e)
        {
            var bank = (from Item item in this.lstBankItems.Items
                        where item.Id != 0
                        select item).ToList();
            var safe = (from Item item in this.lstSafeItems.Items
                        where item.Id != 0
                        select item).ToList();

            bank.ForEach(x => { if (x.MaxStack > 1) x.Count = x.Stack = 999; });
            safe.ForEach(x => { if (x.MaxStack > 1) x.Count = x.Stack = 999; });
        }

        /// <summary>
        /// Click handler to clear the bank.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClearBank_Click(object sender, RoutedEventArgs e)
        {
            var bank = (from Item item in this.lstBankItems.Items
                        where item.Id != 0
                        select item).ToList();
            bank.ForEach(x => { x.SetItem(0); x.Count = x.Stack = 0; });
        }

        /// <summary>
        /// Click handler to clear the safe.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClearSafe_Click(object sender, RoutedEventArgs e)
        {
            var safe = (from Item item in this.lstSafeItems.Items
                        where item.Id != 0
                        select item).ToList();
            safe.ForEach(x => { x.SetItem(0); x.Count = x.Stack = 0; });
        }

        /// <summary>
        /// Event handler to update the selected item. Deselects other items.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstBankItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            this.lstSafeItems.SelectedIndex = -1;
        }

        /// <summary>
        /// Event handler to updae the selectd item. Deselects other items.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstSafeItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            this.lstBankItems.SelectedIndex = -1;
        }

        /// <summary>
        /// Enables right-click 'duping' of items inside player bank.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstBankItems_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var item = this.lstBankItems.SelectedItem as Item;

            if (item != null)
            {
                if (this.lstBankItemList.SelectedItem is Item)
                {
                    item.SetItem((this.lstBankItemList.SelectedItem as Item).Id);
                    item.Count = item.Stack = (this.lstBankItemList.SelectedItem as Item).MaxStack;

                    Int32 nCount = 0;
                    if (Int32.TryParse(this.txtBankAmount.Text, out nCount))
                    {
                        item.Count = item.Stack = nCount;
                    }

                    if (item.Id == 0)
                    {
                        item.Count = item.Stack = 0;
                        return;
                    }
                }
                if (this.cboBankItemPrefixList.SelectedItem is ItemPrefix)
                {
                    item.Prefix = (byte)(cboBankItemPrefixList.SelectedItem as ItemPrefix).Id;
                }
            }
        }

        /// <summary>
        /// Enables right-click 'duping' of items inside player safe.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstSafeItems_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var item = this.lstSafeItems.SelectedItem as Item;

            if (item != null)
            {
                if (this.lstBankItemList.SelectedItem is Item)
                {
                    item.SetItem((this.lstBankItemList.SelectedItem as Item).Id);
                    item.Count = item.Stack = (this.lstBankItemList.SelectedItem as Item).MaxStack;

                    Int32 nCount = 0;
                    if (Int32.TryParse(this.txtBankAmount.Text, out nCount))
                    {
                        item.Count = item.Stack = nCount;
                    }

                    if (item.Id == 0)
                    {
                        item.Count = item.Stack = 0;
                        return;
                    }
                }
                if (this.cboBankItemPrefixList.SelectedItem is ItemPrefix)
                {
                    item.Prefix = (byte)(cboBankItemPrefixList.SelectedItem as ItemPrefix).Id;
                }
            }
        }
    }
}
